#include "DeBruijnGraphBuilder.h"
#include <iostream>
#include <fstream>
#include <ctime>

DeBruijnGraphBuilder::DeBruijnGraphBuilder(AbstractReader& reader, bool inward, int kmerThreshold)
	: m_readFacts( new ReadInputFacts(reader.getReadCount()) ),
	m_graph( NULL ), m_inward(inward)
{
	cout <<"Start build debuijn graph..." <<endl;

	// build graph without reads info
	KmerCounter* kmerCounter = new KmerCounter(reader, kmerThreshold);
	m_graph = new DeBruijnGraph(kmerCounter->bucketTrustedCount());
	for (KmerCounter::iterator it = kmerCounter->begin(); it != kmerCounter->end(); ++it) {
		if (it->second >= kmerThreshold) {
			m_graph->insertVertex(it->first, &(KmerVertex()));
		}
	} // for (KmerCounter::iterator it = kmerCounter->begin(); it != kmerCounter->end(); ++it)
	delete kmerCounter;
	kmerCounter = NULL;
	KmerCounter::CounterMap::map_t::destroyPool();

	reader.reset();
	GCOUNT_T numOfRead = m_readFacts->numOfRead();
	GID_T kmerCnt = 0;
	clock_t DiskTimeElapse=0;
	clock_t AnalyTimeElapse=0;
	clock_t NowTime;
	clock_t StartTime=clock();
	char *buffer;
	int readLen;
	GID_T readID;
	KmerVertex *vertex,*twinVertex;
	CompressedKmer kmer;
	CompressedKmer rkmer;
	for (GCOUNT_T i = 0; i < numOfRead; ++i)
	{
		NowTime=clock();
		buffer = reader.getRead();
		DiskTimeElapse+=(clock()-NowTime);
		readLen = strlen(buffer);
		if (readLen < KmerVertex::getLength())
			continue;

		readID = reader.getID();
		if (! (readID % 10000)) {
			cout << "Having read " << readID << " reads." <<endl;
		}
		int numKmer = readLen - KmerVertex::getLength() + 1;

		for (int j = 0; j < numKmer; ++j) {
			if (!KmerVertex::checkKmerString(buffer + j)) {
				j += KmerVertex::getLength() - 1;
				continue;
			}
			kmer.compress(buffer + j);
			kmer.reverse(rkmer);
			vertex = m_graph->getVertex(kmer);
			//if (vertex==NULL) {
			//	kmerCnt += 2;
			//	if ((m_inward && readID % 2) || !(m_inward || readID % 2)) { // odd
			//		vertex = &(KmerVertex(readID, -j));
			//		twinVertex = &(KmerVertex(-readID, KmerVertex::getLength() + 1 + j - readLen));
			//	} // if (readID % 2)
			//	else { // even
			//		vertex = &(KmerVertex(readID, KmerVertex::getLength() + 1 + j - readLen));
			//		twinVertex = &(KmerVertex(-readID, -j));
			//	}
			//	//vertex->SetTwinVertex(twinVertex);
			//	//twinVertex->SetTwinVertex(vertex);
			//	if (! (kmerCnt % 10000)) {
			//		cout << kmerCnt << "kmers created." <<endl;
			//	}
			//	m_graph->insertVertex(kmer, vertex);
			//	m_graph->insertVertex(rkmer, twinVertex);
			//} // if (vertex==NULL) 
			if (vertex != NULL) 
			{
				twinVertex = m_graph->getVertex(rkmer);
				if ((m_inward && readID % 2) || !(m_inward || readID % 2)) { // odd
					vertex->UpdateReadInfo(readID, -j);
					twinVertex->UpdateReadInfo(-readID, KmerVertex::getLength() + 1 + j - readLen);
				} // if (readID % 2)
				else { // even
					vertex->UpdateReadInfo(readID, KmerVertex::getLength() + 1 + j - readLen);
					twinVertex->UpdateReadInfo(-readID, -j);
				}
			}
		} // for (int j = 0; j < numKmer; ++j)
	} // for (GCOUNT_T i = 0; i < numOfRead; ++i)

	m_graph->finishBuilding();
	m_readFacts->setReadLength(readLen);
	AnalyTimeElapse=clock()-StartTime;
	cout << "diskTimeElapse:  " << double(DiskTimeElapse) / CLOCKS_PER_SEC << " seconds." << endl;
	cout << "AnalyTimeElapse:  " << double(AnalyTimeElapse) / CLOCKS_PER_SEC << " seconds." << endl;
	cout << "Kmer Num is " << m_graph->numOfVertex() << endl;
	cout <<"Finish build debuijn graph." <<endl;
}


DeBruijnGraphBuilder::~DeBruijnGraphBuilder(void)
{
}

DeBruijnGraph* DeBruijnGraphBuilder::getDeBruijnGraph()
{
	return m_graph;
}

ReadInputFacts* DeBruijnGraphBuilder::getReadFacts()
{
	return m_readFacts;
}
